/* simple tool to read and write todos in ~/Documents/todo.txt
 * option explanation:
 * -l: print the file
 * -n: create a new todo to the file(parameter value is the todo string)
 * -d: remove one certain todo(parameter value is todo id)
 * status code explanation:
 * 1: arguments fault
 * 2: file fault
 * 3: id number fault
 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>

// macros
#define MAXSIZ  256
#define FPATH   "/Documents/.todo.txt"
#define TMPPATH "/Documents/.todo.txt.tmp"
#define HOME    getenv("HOME")

// variables
static FILE *fp;

// functions
static void
usage(char *cmd)
{
  printf("Usage: %s [OPTION] ...\n", cmd);
  printf("\t\t-l\n");
  printf("\t\t-n\t[TODO STR]\n");
  printf("\t\t-d\t[TODO ID]\n");
}

// '-l' handler
static void
printfile(char *cmd, char *fpath)
{
  if ((fp = fopen(fpath, "r")) == NULL) {
    fprintf(stderr, "%s: can't get access to %s\n", cmd, fpath);
    exit(2);
  }

  int c;
  int cnt = 0;
  printf("\n");
  while ((c = getc(fp)) != EOF) {
    putchar(c);
    if (c == '-') {
      printf("[%d]", cnt);
      cnt++;
    }
  }
  fclose(fp);
  return;
}

// '-n' handler
static void
newtodo(char *cmd, char *fpath, char *todo)
{
  if ((fp = fopen(fpath, "a")) == NULL) {
    fprintf(stderr, "%s: can't get access to %s\n", cmd, fpath);
    exit(2);
  }
  fprintf(fp, "- %s\n\n", todo);
  fclose(fp);
  return;
}

// '-d' handler
static void
deltodo(char *cmd, char *fpath, char *id)
{
  // judge if the id string is a positive digit(or greater than zero)
  char *str = id;
  while (*str) {
    if (!isdigit(*str++)) {
      fprintf(stderr, "%s: id number must be non-negative digit\n", cmd);
      exit(3);
    }
  }
  int idx = atoi(id);

  // access to todo.txt
  if ((fp = fopen(fpath, "r")) == NULL) {
    fprintf(stderr, "%s: can't get access to %s\n", cmd, fpath);
    exit(2);
  }

  // create todo.txt.tmp file
  char *tmpfile = (char *)malloc(sizeof(char) * MAXSIZ);
  strcpy(tmpfile, HOME);
  tmpfile = strcat(tmpfile, TMPPATH);
  FILE *tmpfp;
  if ((tmpfp = fopen(tmpfile, "w+")) == NULL) {
    fprintf(stderr, "%s: can't get access to %s\n", cmd, tmpfile);
    exit(2);
  }

  // copy source file to temporary file(tmp)
  int cnt = 0,
      c;
  while ((c = getc(fp)) != EOF) {
    if (c == '-') {
      if (cnt++ == idx) {
        while ((c = getc(fp)) != '-' && c != EOF)
          ;
        if (c == EOF)
          break;
      }
    }
    putc(c, tmpfp);
  }
  if (idx >= cnt) {
    fprintf(stderr, "%s: id number %d out of range\n", cmd, idx);
  }

  // copy back to source file(todo.txt)
  fp = freopen(fpath, "w", fp);
  tmpfp = freopen(tmpfile, "r", tmpfp);
  while ((c = getc(tmpfp)) != EOF) {
    putc(c, fp);
  }

  // clean up
  fclose(fp);
  fclose(tmpfp);
  if (remove(tmpfile)) {
    fprintf(stderr, "%s: can't remove file %s\n", cmd, tmpfile);
    exit(2);
  }
  free(tmpfile);
  return;
}

int main(int argc, char *argv[])
{
  // 0. check parameters
  if (argc < 2 || argc > 3 || *argv[1]++ != '-') {
    usage(argv[0]);
    exit(1);
  }

  // 1. check if the file '~/Documents/todo.txt' is accessible
  char *fpath = (char *)malloc(sizeof(char) * MAXSIZ);
  strcpy(fpath, HOME);
  fpath = strcat(fpath, FPATH);
  if ((fp = fopen(fpath, "r+")) == NULL) {
    fprintf(stderr, "%s: can't get access to %s\n", argv[0], fpath);
    exit(2);
  }
  fclose(fp);

  // 2. handlers
  switch (*argv[1]) {
    case 'l':
      printfile(argv[0], fpath);
      break;
    case 'n':
      if (argc != 3) {
        fprintf(stderr, "%s: [-n] accepts one and only one todo string\n", argv[0]);
        exit(1);
      }
      newtodo(argv[0], fpath, argv[2]);
      break;
    case 'd':
      if (argc != 3) {
        fprintf(stderr, "%s: [-d] accepts one and only one todo id\n", argv[0]);
        exit(1);
      }
      deltodo(argv[0], fpath, argv[2]);
      break;
    default:
      usage(argv[0]);
      exit(1);
      break;
  }

  // clean up
  free(fpath);

  return EXIT_SUCCESS;
}
